﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Drawing;
using ITAP.ShprossesBuilder.Modelling.Components;
using ITAP.ShprossesBuilder.Modelling;
using System.Windows.Forms;
using ITAP.Core.Modelling.Primitives;
using ITAP.ShprossesBuilder.Calculations;
using ITAP.Core.Modelling;
using ITAP.Core.Calculations;

namespace ITAP.ShprossesBuilder.Manipulation
{
    public class CommandEditorAddComponentToModel : SerializedUndoRedo, IModelComponentCommand, IModelVisitor
    {
       
        Model model = null;
//        private IComponent undoRemoveComponent;

  //      private IComponent redoAddComponent;

        private ModelPoint pointToInsert;

        private IComponent component;

        private MouseManagerEvent mouseEvent;

        public MouseManagerEvent MouseEvent
        {
            get { return mouseEvent; }
            set { mouseEvent = value; }
        }

        public bool ExecuteImmediately
        {
            get { return false; }
            set { }
        }
        private string name;
        private List<IComponent> components;
        private Point mouseUpPoint;
        #region IModelControlCommand Members

        public ModelControl ModelControl
        {
            get
            {
                return modelControl;
            }
            set
            {
                modelControl = value;
            }
        }

        public System.Drawing.Point MouseDownPoint
        {
            get
            {
                return mouseUpPoint;
            }
            set
            {
                mouseUpPoint = value;
            }
        }

        public System.Drawing.Point MouseUpPoint
        {
            get
            {
                return mouseUpPoint;
            }
            set
            {
                mouseUpPoint = value;
            }
        }

        public System.Drawing.Point MouseMovePoint
        {
            get
            {
                return mouseUpPoint;
            }
            set
            {
                mouseUpPoint = value;
            }
        }

        #endregion

        #region ICommand Members

        public void StartExecute()
        {
           
            ModelCell cell = modelControl.ModelContainer.ActiveCell as ModelCell;

            if (cell == null)
                return;

            this.model = cell.Model;
            undoModelContainer = (ModelContainer)modelControl.ModelContainer.Clone();
            
            double offset = 0;
            // При выполнении команды нужно добавить в список ComponentsForProcessing компоненты, которые будут 
            // добавляться. 
            foreach(IComponent component in this.components)
            {
                ModelPoint pointToInsert = modelControl.CoordinateConverter.ScreenPointToModelPoint(mouseUpPoint, modelControl.ClientRectangle.Width, modelControl.ClientRectangle.Height, modelControl.ModelContainer.BoundingBox, modelControl.Camera);
                pointToInsert.X += offset;
                this.pointToInsert = pointToInsert;

                component.MoveTo(pointToInsert);

                List<IComponent> components = modelControl.ModelContainer.GetComponentsByPoint(pointToInsert, 10);                
                IComponent componentForInserting = null;
                int minIndex = int.MaxValue;
                foreach(IComponent _component in components)
                    if (this.insertPriority.Contains(_component.GetType()))
                    {
                        if (this.insertPriority.IndexOf(_component.GetType()) < minIndex)
                        {
                            minIndex = this.insertPriority.IndexOf(_component.GetType());
                            componentForInserting = _component;
                        }
                    }

                if (componentForInserting == null)
                    return;

                this.component = component;                

                this.modelControl.DeselectAll();

                componentForInserting.AcceptVisitor(this);

                //componentForInserting.AddInnerComponent((IComponent)component.Clone());
            }
        }

        public void Execute()
        {
        }

        public void EndExecute()
        {
        }

        public bool CanUndo
        {
            get { return true; }
        }

        #endregion

        #region ICloneable Members

        public object Clone()
        {
            CommandEditorAddComponentToModel clone = new CommandEditorAddComponentToModel(modelControl, insertPriority.ToArray(), name);

            if (this.undoModelContainer != null)
                clone.undoModelContainer = (ModelContainer)this.undoModelContainer.Clone();
            if (this.redoModelContainer != null)
                clone.redoModelContainer = (ModelContainer)this.redoModelContainer.Clone();
            clone.modelControl = this.modelControl;
            clone.MouseEvent = this.MouseEvent;
            clone.ExecuteImmediately = this.ExecuteImmediately;
//            clone.model = this.model;
            clone.ComponentsForProcessing = new List<IComponent>(this.ComponentsForProcessing);
            clone.MouseDownPoint = this.MouseDownPoint;
            clone.MouseMovePoint = this.MouseMovePoint;
            clone.MouseUpPoint = this.MouseUpPoint;
            return clone;
        }

        #endregion

        #region IModelComponentCommand Members

        public List<ITAP.ShprossesBuilder.Modelling.Components.IComponent> ComponentsForProcessing
        {
            get 
            {
                return components;
            }
            set
            {
                components = value;
            }
        }

        private List<Type> insertPriority;

        public CommandEditorAddComponentToModel(ModelControl modelControl, Type[] insertPriority, string name)
        {
            this.modelControl = modelControl;
            this.insertPriority = new List<Type>(insertPriority);
            this.name = name;
            this.modelControl = modelControl;
            components = new List<IComponent>();
        }

        #endregion

        #region ICommand Members


        public string Name
        {
            get { return "Добавить элемент в модель"; }
        }

        #endregion

        #region ICommand Members


        public bool IsNeedModelUpdate
        {
            get { return true; }
        }

        #endregion

        #region IModelVisitor Members

        public void Visit(Model model)
        {
            model.AddInnerComponent(component);
        }

        public void Visit(Connector connector)
        {
        }

        public void Visit(Shpross shpross)
        {
            if (component is Shpross)
            {
                Shpross newShpross = component as Shpross;
                Model model = shpross.Parent as Model;
                newShpross.MoveStartPointTo(shpross.StartPoint);
                newShpross.MoveEndPointTo(shpross.EndPoint);
                newShpross.Height = shpross.Height;
                model.RemoveInnerComponent(shpross);
                model.AddInnerComponent(newShpross);
            }
            else
            {
                // Пока что в профиль можно добавлять только соединители в рамку (SpacerConnector).
                if (!(component is SpacerConnector))
                    return;

                //            shpross.SelectByPoint(pointToInsert);
                SpacerConnector spacerConnector = component as SpacerConnector;
                if (ModelCalculations.GetDistance(pointToInsert, shpross.StartPoint) < ModelCalculations.GetDistance(pointToInsert, shpross.EndPoint))
                {
                    shpross.StartSpacerConnector = (SpacerConnector)spacerConnector.Clone();
                    shpross.FitStartSpacerConnector();
                }
                else
                {
                    shpross.EndSpacerConnector = (SpacerConnector)spacerConnector.Clone();
                    shpross.FitEndSpacerConnector();
                }
            }
        }

        public void Visit(Spacer spacer)
        {
        }

        public void Visit(ShprossConnectorStub stub)
        {
        }

        public void Visit(ShprossConnector shprossConnector)
        {
            if (component is ShprossConnector)
            {
                Model model = shprossConnector.Parent as Model;
                
                ShprossConnector newConnector = component as ShprossConnector;
                newConnector.MoveTo(shprossConnector.Position);
                model.RemoveInnerComponent(shprossConnector);
                model.AddInnerComponent(newConnector);
            }
            else
                shprossConnector.AddInnerComponent((IComponent)component.Clone());
        }

        public void Visit(SpacerElement spacerElement)
        {
        }

        public void Visit(SpacerConnector spacerConnector)
        {
            spacerConnector.AddInnerComponent((IComponent)component.Clone());
        }

        public void Visit(ModelCell modelCell)
        {
        }

        public void Visit(ModelContainer modelContainer)
        {
        }

        public void Visit(StickConnector stickConnector)
        {
            stickConnector.AddInnerComponent((IComponent)component.Clone());
//            componentForInserting.AddInnerComponent((IComponent)component.Clone());
        }

        public void Visit(SnapOnCap snapOnCap)
        {

        }

        #endregion

        #region IModelVisitor Members


        public void Visit(ShprossEndToEndConnector endToEndConnector)
        {
            IComponent parent = endToEndConnector.Parent;
            if (component is ShprossConnector)
            {
                component.SerialNumber = 0;
                component.MoveTo(endToEndConnector.Position);
                parent.RemoveInnerComponent(endToEndConnector);
                model.Update();
                model.AddInnerComponent(component);
            }
            else            
                endToEndConnector.AddInnerComponent((IComponent)component.Clone());
        }

        #endregion

        #region IModelVisitor Members


        public void Visit(ShprossChain shprossChain)
        {
   //         throw new NotImplementedException();
        }

        #endregion

        #region IModelVisitor Members


        public void Visit(SpacerContainer spacerContainer)
        {
          //  throw new NotImplementedException();
        }

        #endregion

        #region IModelVisitor Members


        public void Visit(CrossConnector crossConnector)
        {
            crossConnector.AddInnerComponent((IComponent)this.component.Clone());
         //   throw new NotImplementedException();
        }

        #endregion

        #region ICommand Members


        //List<IComponent> copiedComponents = new List<IComponent>();
        //public bool Undo()
        //{
        //    copiedComponents.Clear();
        //    foreach (IComponent component in components)
        //        copiedComponents.Add(component.Copy());

        //    foreach(IComponent component in components)
        //        this.model.RemoveInnerComponent(component);

        //    return true;
        //}

        //public bool Redo()
        //{
        //    foreach (IComponent component in copiedComponents)
        //        this.model.AddInnerComponent(component);

        //    components.Clear();
        //    foreach (IComponent component in copiedComponents)
        //        components.Add(component);
        //    return true;
        //}

        #endregion

        public override string ToString()
        {
            return this.Name;
        }

        #region ICommand Members



        private bool enabled = true;
        public bool Enabled
        {
            get
            {
                return enabled;
            }
            set
            {
                enabled = value;
            }
        }

        #endregion

        #region ICommand Members


        public bool IsNeedVisitorsUpdate
        {
            get { return true; }
        }

        #endregion
    }
}
